package com.googlecode.animator.view.topmenu
{
	import com.googlecode.animator.data.Notifications;
	import com.googlecode.animator.model.ProjectSettingsProxy;
	
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.net.FileFilter;
	
	import mx.controls.Alert;
	import mx.events.CloseEvent;
	import mx.events.MenuEvent;
	
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;
	
	/**
	 * Integrates the TopMenu view component with the PureMVC framework.
	 * 
	 * Note: Instances of this Mediator may be dynamically created and removed by the application. 
	 * @author Martin
	 */
	public class TopMenuMediator extends Mediator
	{
		/**
		 * PureMVC identifier. 
		 */
		public static const NAME:String = "TopMenuMediator";
		
		/**
		 * Remembers if a new project is to be opened. 
		 */
		private var _newProjectAfterSaving:Boolean = false;
		
		/**
		 * Remembers if a project is to be opened from XML. 
		 */
		private var _openProjectAfterSaving:Boolean = false;
		
		/**
		 * Constructor. 
		 * @param viewComponent
		 * 
		 */
		public function TopMenuMediator(viewComponent:TopMenu)
		{
			super(NAME, viewComponent);
		}
		
		/**
		 * Sets up event listeners to handle menu interactions. 
		 * 
		 */
		override public function onRegister():void
		{
			viewRef.mainMenu.addEventListener(MenuEvent.CHANGE, onMenuItemClick);
		}
		
		/**
		 * Clean up. 
		 * 
		 */
		override public function onRemove():void
		{
			viewRef.mainMenu.removeEventListener(MenuEvent.CHANGE, onMenuItemClick);
		}
		
		/**
		 * Register interest in notifications. 
		 * @return 
		 * 
		 */
		override public function listNotificationInterests():Array
		{
			var list:Array = super.listNotificationInterests();
			
			list.push(Notifications.PROJECT_SAVED);
			
			return list;
		}
		
		/**
		 * Handle notifications sent by PureMVC. 
		 * @param notification
		 * 
		 */
		override public function handleNotification(notification:INotification):void
		{
			super.handleNotification(notification);
			
			switch(notification.getName())
			{
				case Notifications.PROJECT_SAVED:
					
					handleProjectSaved();
					
					break;
			}
		}
		
		/**
		 * Responds to the project being saved. 
		 * 
		 */
		protected function handleProjectSaved():void
		{
			if(_newProjectAfterSaving)
			{
				sendNotification(Notifications.NEW_PROJECT);
				_newProjectAfterSaving = false;
			}
			
			if(_openProjectAfterSaving)
			{
				openProject();
				_openProjectAfterSaving = false;
			}
		}
		
		//////////////////////////////////////////////////////////////////////
		//
		// Event handlers
		//
		//////////////////////////////////////////////////////////////////////
		
		/**
		 * Handles selection of menu items. 
		 * @param evt
		 * 
		 */
		protected function onMenuItemClick(evt:MenuEvent):void
		{
			switch(String(evt.item.@data))
			{
				case "New":
					
					newProjectSelected();
					
					break;
				
				case "Save":
					
					saveProjectSelected();
					
					break;
				
				case "Save as":
					
					saveProjectSelected(true);
					
					break;
				
				case "Open":
					
					openProjectSelected();
					
					break;
			}
		}
		
		/**
		 * Responds to the New Project main menu item being clicked.
		 * 
		 */
		protected function newProjectSelected():void
		{
			// protect against the user accidently destroying all data
			Alert.show("Do you want to save project?", "Warning!", Alert.YES | Alert.NO | Alert.CANCEL, null, onNewProjectAlert);
		}
		
		/**
		 * Attempting to open a new project causes an alert box to pop up. This  is
		 * because all data will be destroyed. The user is asked whether 
		 * or not to save the project. 
		 * @param evt
		 * 
		 */
		protected function onNewProjectAlert(evt:CloseEvent):void
		{
			switch(evt.detail)
			{
				case Alert.YES:
				
					// the user has requested that the project be saved
					_newProjectAfterSaving = true;
					saveProjectSelected();
					//sendNotification(Notifications.SAVE_PROJECT);
					
					break;
				
				case Alert.NO:
					
					// the user would like to go ahead and create new project
					sendNotification(Notifications.NEW_PROJECT);
					
					break;
				
				case Alert.CANCEL:
					
					// do nothing.
					
					break;
			}
		}
		
		/**
		 * Calling this function opens a file browser in preparation for
		 * saving the project.
		 * 
		 * @param saveAs
		 * 
		 */
		protected function saveProjectSelected(saveAs:Boolean = false):void
		{
			var file:File;
			
			// if no save path has been set, go and get one
			if(settings.savePath == null || saveAs == true)
			{
				file = new File();
				
				try
				{
					file.addEventListener(Event.SELECT, onSaveSelect);
					file.addEventListener(Event.CANCEL, onSaveCancel);
					file.browseForSave("Save Project");
				}
				catch (error:Error)
				{
    				trace("Failed:", error.message);
				}	
			}else
			{
				sendNotification(Notifications.SAVE_PROJECT);
			}
			
		}
		
		/**
		 * Responds to the user selecting a file path with which to save the project. 
		 * @param evt
		 * 
		 */
		protected function onSaveSelect(evt:Event):void
		{
			(evt.target as File).removeEventListener(Event.SELECT, onSaveSelect);
			(evt.target as File).removeEventListener(Event.CANCEL, onSaveCancel);
			
			sendNotification(Notifications.SAVE_PROJECT, (evt.target as File).url);
		}
		
		/**
		 * Responds to the user cancelling a file save operation. 
		 * @param evt
		 * 
		 */
		protected function onSaveCancel(evt:Event):void
		{	
			(evt.target as File).removeEventListener(Event.SELECT, onSaveSelect);
			(evt.target as File).removeEventListener(Event.CANCEL, onSaveCancel);
			
			_newProjectAfterSaving = false;
			_openProjectAfterSaving = false;
		}
		
		protected function openProjectSelected():void
		{
			Alert.show("Do you want to save project?", "Warning!", Alert.YES | Alert.NO | Alert.CANCEL, null, onOpenProjectAlert);
		}
		
		/**
		 * Attempting to open a project causes an alert box to pop up. This  is
		 * because all data will be destroyed. The user is asked whether 
		 * or not to save the project. 
		 * @param evt
		 * 
		 */
		protected function onOpenProjectAlert(evt:CloseEvent):void
		{	
			switch(evt.detail)
			{
				case Alert.YES:

					_openProjectAfterSaving = true;
					saveProjectSelected();
					
					break;
				
				case Alert.NO:
					
					openProject();
					
					break;
				
				case Alert.CANCEL:
					
					// do nothing.
					
					break;
			}

		}
		
		/**
		 * Calling this function opens a file browser in order to select
		 * the file to open.
		 * 
		 * @param saveAs
		 * 
		 */
		protected function openProject():void
		{
			var file:File = new File();
			var ff:FileFilter = new FileFilter("Project file", "*.xml;");
			
			try
			{
				file.addEventListener(Event.SELECT, onOpenSelect);
				file.addEventListener(Event.CANCEL, onOpenCancel);
				file.browseForOpen("Open Project", [ff]);
			}
			catch (error:Error)
			{
				trace("Failed:", error.message);
			}  
		}
		
		/**
		 * Responds to the user selecting a file path with which to open an existing project. 
		 * @param evt
		 * 
		 */
		protected function onOpenSelect(evt:Event):void
		{
			(evt.target as File).removeEventListener(Event.SELECT, onOpenSelect);
			(evt.target as File).removeEventListener(Event.CANCEL, onOpenCancel);
			
			sendNotification(Notifications.OPEN_PROJECT, (evt.target as File).url);
			//_openProjectFilepath = (evt.target as File).url;

		}
		
		/**
		 * Responds to the user cancelling a file open operation. 
		 * @param evt
		 * 
		 */
		protected function onOpenCancel(evt:Event):void
		{
			(evt.target as File).removeEventListener(Event.SELECT, onOpenSelect);
			(evt.target as File).addEventListener(Event.CANCEL, onOpenCancel);
		}
		
		/////////////////////////////////////////////////////////////////
		// Utility Functions
		/////////////////////////////////////////////////////////////////
		
		protected function get viewRef():TopMenu
		{
			return viewComponent as TopMenu;
		}
		
		protected function get settings():ProjectSettingsProxy
		{
			return facade.retrieveProxy(ProjectSettingsProxy.NAME) as ProjectSettingsProxy;
		}
	}
}